﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using NHibernate.Criterion;

using ProjectBase.Core;

namespace $safeprojectname$
{
    public static partial class DaoExtensions
    {
        #region struct Compare

        public static IList<ICriterion> AddCompare<TFilter, TResult>(this IList<ICriterion> criteria, TFilter filter
            , Expression<Func<TFilter, TResult?>> expr)
            where TFilter : Core.IFilter
            where TResult : struct
        {
            MemberExpression body;
            switch (expr.Body.NodeType)
            {
                case ExpressionType.Convert: // short, sbyte ...
                    var unnary = expr.Body as UnaryExpression;
                    if (unnary.Operand.NodeType
                        != ExpressionType.MemberAccess)
                    {
                        throw new NotSupportedException(
                            "Provided 'Expression<Func<TFilter, TResult?>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
                    }
                    body = unnary.Operand as MemberExpression;
                    break;

                case ExpressionType.MemberAccess: // 4 byte and more
                    body = expr.Body as MemberExpression;
                    break;

                default:
                    throw new NotSupportedException(
                        "Provided 'Expression<Func<TFilter, TResult?>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
            }

            var name = body.Member.Name;
            var sign = Sign.Equal;
            if (name.IsEqual("IdExact"))
            {
                name = Constants.Common.ID;
            }
            else if (name.EndsWith("From"))
            {
                name = name.Remove((name.Length - 4));
                sign = Sign.GreaterOrEqual;
            }
            else if (name.EndsWith("To"))
            {
                name = name.Remove((name.Length - 2));
                sign = Sign.LessOrEqual;
            }

            var result = GetCompiled(expr);
            try
            // there must be try for some cases, for instance when the Nested property object is null e.g. entity.Parent.Code
            {
                var value = result(filter);
                // could result in NullReferenceException if the Parent is null (entity.Parent.Code)
                if (value.Is())
                {
                    criteria.Add(new SimpleExpression(name, value, Const.Signs[sign], false));
                }
            }
            catch (NullReferenceException)
            {
                // entity.Parent.Code -> where Parent is null
            }

            return criteria;
        }

        public static IList<ICriterion> AddCompare<TFilter, TResult>(this IList<ICriterion> criteria, TFilter filter
            , Expression<Func<TFilter, TResult?>> expr, Sign sign,
            TResult? value)
            where TFilter : Core.IFilter
            where TResult : struct
        {
            if (value.IsNull())
            {
                return criteria;
            }
            MemberExpression body;
            switch (expr.Body.NodeType)
            {
                case ExpressionType.Convert: // short, sbyte ...
                    var unnary = expr.Body as UnaryExpression;
                    if (unnary.Operand.NodeType
                        != ExpressionType.MemberAccess)
                    {
                        throw new NotSupportedException(
                            "Provided 'Expression<Func<TFilter, TResult?>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
                    }
                    body = unnary.Operand as MemberExpression;
                    break;

                case ExpressionType.MemberAccess: // 4 byte and more
                    body = expr.Body as MemberExpression;
                    break;

                default:
                    throw new NotSupportedException(
                        "Provided 'Expression<Func<TFilter, TResult?>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
            }
            criteria.Add(new SimpleExpression(body.Member.Name, value, Const.Signs[sign], false));

            return criteria;
        }

        public static IList<ICriterion> AddCompare<TFilter, TResult>(this IList<ICriterion> criteria, TFilter filter
            , Expression<Func<TFilter, TResult>> expr, Sign sign, TResult? value)
            where TFilter : Core.IFilter
            where TResult : struct
        {
            if (value.IsNull())
            {
                return criteria;
            }
            MemberExpression body;
            switch (expr.Body.NodeType)
            {
                case ExpressionType.Convert: // short, sbyte ...
                    var unnary = expr.Body as UnaryExpression;
                    if (unnary.Operand.NodeType
                        != ExpressionType.MemberAccess)
                    {
                        throw new NotSupportedException(
                            "Provided 'Expression<Func<TFilter, TResult>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
                    }
                    body = unnary.Operand as MemberExpression;
                    break;

                case ExpressionType.MemberAccess: // 4 byte and more
                    body = expr.Body as MemberExpression;
                    break;

                default:
                    throw new NotSupportedException(
                        "Provided 'Expression<Func<TFilter, TResult>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
            }
            criteria.Add(new SimpleExpression(body.Member.Name, value, Const.Signs[sign], false));

            return criteria;
        }

        #endregion struct Compare

        #region struct Equal (abbrev for Compare)

        public static IList<ICriterion> AddEqual<TFilter, TResult>(this IList<ICriterion> criteria, TFilter filter
            , Expression<Func<TFilter, TResult?>> expr, TResult? value)
            where TFilter : Core.IFilter
            where TResult : struct
        {
            return AddCompare(criteria, filter, expr, Sign.Equal, value);
        }

        public static IList<ICriterion> AddEqual<TFilter, TResult>(this IList<ICriterion> criteria, TFilter filter
            , Expression<Func<TFilter, TResult>> expr, TResult? value)
            where TFilter : Core.IFilter
            where TResult : struct
        {
            return AddCompare(criteria, filter, expr, Sign.Equal, value);
        }

        public static IList<ICriterion> AddNotEqual<TID>(this IList<ICriterion> criteria, string name, TID value)
        {
            if (value.Is())
            {
                criteria.Add(new SimpleExpression(name, value, Const.NotEqual, false));
            }
            return criteria;
        }

        #endregion struct Equal (abbrev for Compare)
    }
}